package codename.carrot.bomberman.activity;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import android.app.Activity;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Toast;
import codename.carrot.bomberman.R;
import codename.carrot.bomberman.adapters.PlayerArrayAdapter;
import codename.carrot.bomberman.game.gamemessages.GameInitMessage;
import codename.carrot.bomberman.game.gamemessages.PlayerJoinMessage;
import codename.carrot.bomberman.game.gamemessages.PlayerQuitMessage;
import codename.carrot.bomberman.game.listener.PlayerStateListener;
import codename.carrot.bomberman.game.networkobjects.DroidPoint;
import codename.carrot.bomberman.models.Player;
import codename.carrot.bomberman.models.Player.PlayerColor;
import codename.carrot.bomberman.network.NetworkConnection;
import codename.carrot.bomberman.network.NetworkConnection.NetworkState;
import codename.carrot.bomberman.network.client.ClientPostOffice;
import codename.carrot.bomberman.network.listener.NetworkStateListener;
import codename.carrot.bomberman.network.server.ServerPostOffice;

/**
 *  Abstract class which handles general elements regarding the gamelobby, as well as providing functionality for subclasses
 * @author Group A4 
 * @see ServerGameLobbyActivity
 * @see ClientGameLobbyActivity
 */

abstract class GameLobbyActivity extends Activity implements OnClickListener, NetworkStateListener, PlayerStateListener {
	
    /**
     * String for debugging.
     */
	private final String DEBUG = this.getClass().getSimpleName();

	/**
	 * The button used on the server for starting a game.
	 */
	protected Button btnStartGame;
	/**
	 * The arrray adapter holding the names of connected players, used to display the players in the lobby.
	 */
	protected PlayerArrayAdapter playerArray;
	/**
	 * The progress bar/throbber to show a that the lobby is waiting for connections or game start.
	 */
	protected ProgressBar progressBar;
	/**
	 * The local player.
	 */
	protected Player myPlayer;
	/**
	 * The nickname of the local player.
	 */
	protected String nickname,
	/**
	 * The ip-address the client is to connect to.
	 */
	ipString;
	/**
	 * The android wi-fi manager, used for requesting and checking that the wi-fi is connected.
	 */
	protected WifiManager wifiManager;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
		NetworkConnection.getInstance().addStateListener(this);
		ClientPostOffice.getInstance().addPlayerStateListener(this);
		wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
		int ip = wifiManager.getConnectionInfo().getIpAddress();
		ipString = String.format("%d.%d.%d.%d", (ip & 0xff), (ip >> 8 & 0xff),(ip >> 16 & 0xff), (ip >> 24 & 0xff));

		Intent intent = getIntent();
		nickname = intent.getExtras().getString("nickname");
		setContentView(R.layout.game_lobby);

		// SET LAYOUT FOR CLIENT/SERVER VIEW
		playerArray = new PlayerArrayAdapter(this, R.layout.listview_entry,R.id.listview_entry_list);

		ListView pairedListView = (ListView) this.findViewById(R.id.lvGameLobbyPlayers);
		pairedListView.setAdapter(playerArray);

		// SET PROGRESS BAR FOR WAITING FOR CONNECTIONS
		progressBar = (ProgressBar) this.findViewById(R.id.gameLobbyProgress);
		progressBar.setVisibility(View.INVISIBLE);
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		playerArray.clear();
	}

	@Override
	public void onClick(View v) {}

	@Override
	public void onBackPressed() {
		super.onBackPressed();
		NetworkConnection.getInstance().terminate();
		ClientPostOffice.getInstance().destroy();
		ServerPostOffice.getInstance().destroy();
		this.onDestroy();
	}
	

	/**
	 * This method is called for the game to start, when a GameInitMessage is recivied from the server.
	 * The method is responsible for setting up the game and thereafter calling the GameActivity.
	 * @param gameInitMessage The message that inidicates a game start.
	 */
	protected void startGame(GameInitMessage gameInitMessage) {
		// Set up my initial coordinates
		DroidPoint myInitialPosition = gameInitMessage.getInitialPlayerPosition(myPlayer.getPlayerId());
		myPlayer.setInitialPlayerPosition(myInitialPosition);

		ArrayList<Player> players = new ArrayList<Player>();
		// Sort the array of players by playerId (from low to high)
		// We need to do this in order to make sure the colors for each player
		// is the same on all devices
		for (int i = 0; i < playerArray.getCount(); i++) {
			Player p = playerArray.getItem(i);
			players.add(p);
			// set up initial coords for all players
			DroidPoint initialPlayerPosition = gameInitMessage.getInitialPlayerPosition(p.getPlayerId());
			p.setInitialPlayerPosition(initialPlayerPosition);
		}

		// Sorting the player-array according to playerID
		Collections.sort(players, new Comparator<Player>() {
			@Override
			public int compare(Player p1, Player p2) {
				return p1.getPlayerId() - p2.getPlayerId();
			}
		});
		// Now that the array is sorted, we can set the color for each player
		// ( The array of players will be sorted in the same way on all
		// connected devices )
		for (int i = 0; i < players.size(); i++) {
			// Get the next available color
			if (i < PlayerColor.values().length) {
				PlayerColor color = PlayerColor.values()[i];
				Player p = players.get(i);
				p.setColor(color);
			}
		}

		GameActivity.players = players;
		GameActivity.gameInit = gameInitMessage;
		GameActivity.myPlayer = myPlayer;

		Intent intent = new Intent(this, GameActivity.class);
		startActivity(intent);
	}

	@Override
	public void onStateChange(NetworkState state) {
		if (state == NetworkState.NONE) {
			Toast.makeText(this, "You were disconnected...", Toast.LENGTH_SHORT).show();
			NetworkConnection.getInstance().terminate();
			ClientPostOffice.getInstance().destroy();
			ServerPostOffice.getInstance().destroy();
			this.finish();
		}
		if(state == NetworkState.ERROR){
			Toast.makeText(this, "An error occured while connecting, please try again...", Toast.LENGTH_SHORT).show();
			NetworkConnection.getInstance().terminate();
			ClientPostOffice.getInstance().destroy();
			ServerPostOffice.getInstance().destroy();
			this.finish();
		}
	}

	@Override
	public void onPlayerJoin(PlayerJoinMessage pm, int playerId) {
		// TODO Auto-generated method stub
		Player player = new Player(0, 0, pm.getPlayerId(),pm.getPlayerNickname());
		if (pm.concernsReceiver()) {
			Log.d(DEBUG, "MAKING PLAYER");
			// yay, it concerns me. I should now have been assigned a playerId
			myPlayer = player;
		}
		playerArray.add(player);
	}

	@Override
	public void onInitBeforegame(GameInitMessage gameInit) {
		// LOL
		Log.d(DEBUG, "Got gameMessage!");		
		startGame(gameInit);
	}

	@Override
	public void onPlayerQuit(PlayerQuitMessage pm) {
		Log.d(DEBUG, "PlayerQuit Lobby: " + pm.getPlayerId());
		Player player = null;
		for (int i = 0; i < playerArray.getCount(); i++) {
			if (playerArray.getItem(i).getPlayerId() == pm.getPlayerId()) {
				player = playerArray.getItem(i);
				break;
			}
		}
		
		playerArray.remove(player);
		for (int i = 0; i < playerArray.getCount(); i++) {
			Log.d(DEBUG, "Remaining: " + playerArray.getItem(i).getPlayerId());
		}

	}
}
